﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Cache;
using System.IO;
using ICSharpCode.SharpZipLib.GZip;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using ICSharpCode.SharpZipLib.Zip.Compression;
using System.Drawing;
using Demo.Model;
using System.Text.RegularExpressions;
using System.Web;
using Demo.Site;
using System.Threading;
using System.ComponentModel;

namespace Demo
{
    public abstract class SiteBase
    {


        private CookieContainer _Cookie = new CookieContainer();
        private RequestCachePolicy _DefCachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
        private string _myWebAddress;
        protected const string DefGetCommand = "GET";
        public const int DefMidfielderTime = 45;
        protected const string DefPostCommand = "POST";
        protected const string DefUserAgent = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; .NET4.0E)";
        private char[] _Buffer = new char[2048];
        private BindingList<Company> _Companys = new BindingList<Company>();



        public CookieContainer Cookie
        {
            get
            {
                return this._Cookie;
            }
            protected set
            {
                this._Cookie = value;
            }
        }
        public BindingList<Company> Companys
        {
            get { return this._Companys; }
        }
        public RequestCachePolicy DefCachePolicy
        {
            get
            {
                return this._DefCachePolicy;
            }
        }
        public bool IsMoreThanFive { get; protected set; }
        public virtual string LastReadAddress
        {
            get;
            protected set;
        }
        public virtual string MyWebAddress
        {
            get { return _myWebAddress; }
            protected set { this._myWebAddress = value; }
        }
        public virtual int WebTimeOut
        {
            get
            {
                return 60000;
            }
        }
        public string LastReadHtml { get; protected set; }
        public event EventHandler<InputValidateCodeEventArgs> InputValidateCode;

        protected HttpWebRequest CreateGetRequest(string addressFormat, bool isLogLast = true)
        {
            string requestUriString = string.Format(addressFormat, this.MyWebAddress);
            if (isLogLast)
            {
                this.LastReadAddress = requestUriString;
            }
            HttpWebRequest request = WebRequest.Create(requestUriString) as HttpWebRequest;
            request.Method = "GET";
            request.UserAgent = DefUserAgent;
            request.CachePolicy = this.DefCachePolicy;
            request.CookieContainer = this.Cookie;
            request.Timeout = this.WebTimeOut;
            request.ReadWriteTimeout = this.WebTimeOut;
            request.KeepAlive = true;
            return request;
        }
        protected HttpWebRequest CreatePostRequest(string addressFormat, bool isLogLast = true)
        {
            string requestUriString = string.Format(addressFormat, this.MyWebAddress);
            if (isLogLast)
            {
                this.LastReadAddress = requestUriString;
            }
            HttpWebRequest request = WebRequest.Create(requestUriString) as HttpWebRequest;
            request.Method = "POST";
            request.UserAgent = DefUserAgent;
            request.CachePolicy = this.DefCachePolicy;
            request.CookieContainer = this.Cookie;
            request.Timeout = this.WebTimeOut;
            request.ReadWriteTimeout = this.WebTimeOut;
            request.KeepAlive = true;
            return request;
        }
        protected Stream Gzip(HttpWebResponse response)
        {
            if (response.ContentEncoding.Equals("gzip", StringComparison.OrdinalIgnoreCase))
            {
                return new GZipInputStream(response.GetResponseStream());
            }
            if (!response.ContentEncoding.Equals("deflate", StringComparison.OrdinalIgnoreCase))
            {
                return response.GetResponseStream();
            }
            return new InflaterInputStream(response.GetResponseStream(), new Inflater(false));
        }
        protected string ReadStream(HttpWebResponse response, Encoding encoding)
        {
            return this.ReadStream(response, encoding, this._Buffer, true);
        }
        protected string ReadStream(HttpWebResponse response, Encoding encoding, char[] buffer, bool isLogLast = true)
        {
            string str = string.Empty;
            using (Stream stream = this.Gzip(response))
            {
                using (StreamReader reader = new StreamReader(stream, encoding))
                {
                    int num = 0;
                    StringBuilder builder = new StringBuilder();
                    while (reader.EndOfStream == false)
                    {
                        num = reader.Read(buffer, 0, buffer.Length);
                        builder.Append(buffer, 0, num);
                    }
                    str = builder.ToString();
                    if (isLogLast)
                    {
                        this.LastReadHtml = str;
                    }
                }
            }
            return str;
        }
        protected Image ReadImageStream(HttpWebResponse response)
        {
            try
            {
                using (Stream stream = this.Gzip(response))
                {
                    return Image.FromStream(stream);
                }
            }
            finally
            {
            }
            return null;
        }


        protected abstract HttpWebRequest CreateSearchRequest(string searchCondition, string validateCode);
        protected abstract Image ReadCode();
        protected abstract void ReadInitPage();
        protected abstract bool CheckResult(string html);
        protected abstract void ReadDetailInitPage(Company company);
        protected abstract void BeginComitSearch(string searchCondition, string validateCode, Action<SiteBase> searchCallBack);
        protected abstract void BeginReadDetail(Company company, CompanyDetail companyDetail, Action<Company> callBack);
        /// <summary>
        /// 登记信息
        /// </summary>
        protected abstract void ReadDJXX(string html);
        /// <summary>
        /// 备案信息
        /// </summary>
        protected abstract void ReadBAXX(string html);
        /// <summary>
        /// 行政处罚信息
        /// </summary>
        protected abstract void ReadXZCFXX(string html);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        private static bool CheckUrl(string str)
        {
            if (string.IsNullOrEmpty(str))
            {
                return false;
            }
            return new Regex(@"https?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?", RegexOptions.IgnoreCase).IsMatch(str);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="asyncResult"></param>
        protected virtual void EndSearchRequest(IAsyncResult asyncResult)
        {
            object[] asyncStates = asyncResult.AsyncState as object[];
            HttpWebResponse response = null;
            HttpWebRequest request = null;
            Action<SiteBase> callback = null;
            try
            {
                request = asyncStates[0] as HttpWebRequest;
                callback = asyncStates[1] as Action<SiteBase>;
                response = (HttpWebResponse)request.EndGetResponse(asyncResult);
                string html = HttpUtility.HtmlDecode(this.ReadStream(response, Encoding.UTF8));
                if (CheckResult(html))
                    this.ReadSearchResult(html);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (response != null)
                {
                    response.Close();
                }
                if (request != null)
                {
                    request.Abort();
                }
                if (callback != null)
                    callback(this);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="asyncResult"></param>
        protected virtual void EndReadDetail(IAsyncResult asyncResult)
        {
            object[] asyncStates = asyncResult.AsyncState as object[];
            HttpWebResponse response = null;
            HttpWebRequest request = null;
            Action<Company> callback = null;
            Company company = null;
            CompanyDetail detailType;
            try
            {
                request = asyncStates[0] as HttpWebRequest;
                callback = asyncStates[1] as Action<Company>;
                company = asyncStates[2] as Company;
                detailType = (CompanyDetail)asyncStates[3];

                response = (HttpWebResponse)request.EndGetResponse(asyncResult);
                string html = HttpUtility.HtmlDecode(this.ReadStream(response, Encoding.UTF8));
                if (CheckResult(html))
                {
                    switch (detailType)
                    {
                        case CompanyDetail.登记信息:
                            ReadDJXX(html);
                            break;
                        case CompanyDetail.备案信息:
                            ReadBAXX(html);
                            break;
                        case CompanyDetail.行政处罚信息:
                            ReadXZCFXX(html);
                            break;
                        case CompanyDetail.变更信息:
                            break;
                        default:
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (response != null)
                {
                    response.Close();
                }
                if (request != null)
                {
                    request.Abort();
                }
                if (callback != null)
                    callback(company);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnInputValidateCode(InputValidateCodeEventArgs e)
        {
            if (this.InputValidateCode != null)
            {
                this.InputValidateCode(this, e);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="resultHtml"></param>
        protected virtual void ReadSearchResult(string resultHtml)
        {
            if (resultHtml.Contains("您查询的信息多于5条记录，请输入更精确的查询条件"))
                this.IsMoreThanFive = true;
            resultHtml = this.GetRegValueMatch("<dt>.*</dd>", resultHtml.Replace("\n", "").Replace("\r", "").Trim());
            if (string.IsNullOrEmpty(resultHtml) == false)
            {
                resultHtml = resultHtml.Replace("<dt>", "").Replace("</a>", "")
                    .Replace("<a target=\"_blank\" href=\"../", "")
                    .Replace("<a href=\"../", "")
                    .Replace("<a href=\"", "")
                    .Replace("target=_blank", "")
                    .Replace("<dd>", "").Replace("<span>", "");
                string[] strArray1 = resultHtml.Split(new String[] { "</dd>" }, StringSplitOptions.RemoveEmptyEntries);
                string[] strArray2 = null;
                if (strArray1 != null)
                {

                    Company company = null;
                    string detail = string.Empty;
                    for (int i = 0; i < strArray1.Length; i++)
                    {
                        strArray2 = strArray1[i].Split(new String[] { "</dt>" }, StringSplitOptions.RemoveEmptyEntries);
                        detail = strArray2[1];
                        strArray2 = strArray2[0].Split(new String[] { "\">", "\" >" }, StringSplitOptions.RemoveEmptyEntries);
                        company = new Company();
                        company.RegeditName = strArray2[1];
                        company.RedirectUrl = strArray2[0].Trim();
                        strArray2 = detail.Split(new String[] { "</span>" }, StringSplitOptions.RemoveEmptyEntries);
                        company.RegeditNo = strArray2[0].Split(':')[1];
                        company.LealPerson = strArray2[1].Split(':')[1];
                        company.RegistrationAuthority = strArray2[2].Split(':')[1];
                        company.FoundedTime = strArray2[3].Split(':')[1];
                        company.IsPrivateBuilid = true;
                        company.IsFirstReadDetail = true;
                        this.Companys.Add(company);
                    }

                    if (this.IsMoreThanFive)
                        throw new Exception("您查询的信息多于5条记录，请输入更精确的查询条件!");
                }
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="siteType"></param>
        /// <returns></returns>
        public static SiteBase CreateSite(SiteType siteType)
        {
            SiteBase site = null;
            switch (siteType)
            {
                case SiteType.北京:
                    break;
                case SiteType.天津:
                    break;
                case SiteType.河北:
                    break;
                case SiteType.山西:
                    break;
                case SiteType.内蒙古:
                    break;
                case SiteType.广东:
                    site = new SiteGuangDong();
                    break;
                case SiteType.广西:
                    break;
                default:
                    break;
            }
            return site;
        }
        /// <summary>
        /// 模糊查找指定条件公司信息
        /// </summary>
        /// <param name="searchCondition"></param>
        public void SearchCompany(string searchCondition, Action<SiteBase> searchCallBack)
        {
            try
            {
                string validateCode = string.Empty;
                this.Cookie = new CookieContainer();
                this.Companys.Clear();
                if (CheckUrl(this.MyWebAddress))
                {

                    Image image = this.ReadCode();
                    if (image != null)
                    {
                        using (InputValidateCodeEventArgs args = new InputValidateCodeEventArgs(image, validateCode))
                        {
                            this.OnInputValidateCode(args);
                            validateCode = args.ValidateCode;
                        }
                    }
                    this.BeginComitSearch(searchCondition, validateCode, searchCallBack);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="company"></param>
        public void ReadCompanyDetail(Company company, CompanyDetail companyDetail, Action<Company> callBack)
        {
            try
            {
                if (company.IsFirstReadDetail)
                    this.ReadDetailInitPage(company);
                this.BeginReadDetail(company, companyDetail, callBack);
                company.IsFirstReadDetail = false;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        #region GetRegValue
        protected string[] GetRegKeyValues(string regexValue, string remoteStr)
        {
            Regex regex = new Regex(regexValue, RegexOptions.IgnoreCase);
            MatchCollection matchs = regex.Matches(remoteStr);
            string[] strArray = new string[matchs.Count];
            for (int i = 0; i < matchs.Count; i++)
            {
                object[] args = new object[] { matchs[i].Groups["KEY"].Value, matchs[i].Groups["BUHUO"].Value };
                strArray[i] = string.Format("{0}={1}", args);
            }
            return strArray;
        }
        protected string[] GetRegKeyValuesEncode(string regexValue, string remoteStr)
        {
            Regex regex = new Regex(regexValue, RegexOptions.IgnoreCase);
            MatchCollection matchs = regex.Matches(remoteStr);
            string[] strArray = new string[matchs.Count];
            for (int i = 0; i < matchs.Count; i++)
            {
                object[] args = new object[] { HttpUtility.UrlEncode(matchs[i].Groups["KEY"].Value), HttpUtility.UrlEncode(matchs[i].Groups["BUHUO"].Value) };
                strArray[i] = string.Format("{0}={1}", args);
            }
            return strArray;
        }
        protected string GetRegValue(string regexValue, string remoteStr)
        {
            Regex regex = new Regex(regexValue, RegexOptions.Multiline | RegexOptions.IgnoreCase);
            Match match = regex.Match(remoteStr);
            if (!match.Success)
            {
                return string.Empty;
            }
            return match.Groups["BUHUO"].Value;
        }
        protected bool GetRegValueIsMatch(string regexValue, string remoteStr)
        {
            Regex regex = new Regex(regexValue, RegexOptions.Multiline | RegexOptions.IgnoreCase);
            return regex.IsMatch(remoteStr);
        }
        protected string GetRegValueMatch(string regexValue, string remoteStr)
        {
            Regex regex = new Regex(regexValue, RegexOptions.Multiline | RegexOptions.IgnoreCase);
            return regex.Match(remoteStr).Value;
        }
        protected IList<string> GetRegValueMatches(string regexValue, string remoteStr)
        {
            Regex regex = new Regex(regexValue, RegexOptions.Multiline | RegexOptions.IgnoreCase);
            MatchCollection matchs = regex.Matches(remoteStr);
            IList<string> list = new List<string>();
            foreach (Match match in matchs)
            {
                list.Add(match.Value);
            }
            return list;
        }
        protected string GetRegValueReplace(string regexValue, string remoteStr, string replaceStr)
        {
            Regex regex = new Regex(regexValue, RegexOptions.Multiline | RegexOptions.IgnoreCase);
            return regex.Replace(remoteStr, replaceStr);
        }
        protected string[] GetRegValues(string regexValue, string remoteStr)
        {
            Regex regex = new Regex(regexValue, RegexOptions.IgnoreCase);
            MatchCollection matchs = regex.Matches(remoteStr);
            string[] strArray = new string[matchs.Count];
            for (int i = 0; i < matchs.Count; i++)
            {
                strArray[i] = matchs[i].Groups["BUHUO"].Value;
            }
            return strArray;
        }
        #endregion
    }
}
